<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Strict//EN">
<html>

<head>
<meta http-equiv="Content-Language" content="en-us">
<title>Joint types and operation</title>
<link rel="stylesheet" type="text/css" href="../style.css">
</head>

<body>

<div align="center">
<table class=allEncompassingTable >
 <tr>
  <td >
<p><a href="../index.html" TARGET="_top"><img src="images/homeImg.png"></a></p>



<h1>Joint types and operation</h1>


<p>Compared to another <a href="objects.htm">object</a>, a <a href="joints.htm">joint</a> has two reference frames (visible only if the joint is selected). The first one is the regular reference frame that is fixed and that other objects also have. The second reference frame is not fixed, and will move relative to the first reference frame depending on the joint position (or joint value) that defines its configuration.</p>

<br>
<table class=subsectionTable><tr class=subsectionTd><td class=subsectionTd>
<a name="types"></a>Joint types
</td></tr></table>

<p>4 types of joints are supported:</p>

<p align=center><img src="images/jointDescription1.jpg"></p>
<p class=imageLabel>[Revolute joint, prismatic joint, screw and spherical joint]</p>
<br>

<li><strong>Revolute joints</strong>: revolute joints have one DoF and are used to describe rotational movements (with 1 DoF) between objects. Their configuration is defined by one value that represents the amount of rotation about their first reference frame's z-axis. They can be used as passive joints, or as active joints (motors).<br>
</li>

<li><strong>Prismatic joints</strong>: prismatic joints have one DoF and are used to describe translational movements between objects. Their configuration is defined by one value that represents the amount of translation along their first reference frame's z-axis. They can be used as passive joints, or as active joints (motors).<br>
</li>

<li><strong>Screws</strong>: screws, which can be seen as a combination of revolute joints and prismatic joints (with linked values), have one DoF and are used to describe a movement similar to a screw. A pitch parameter defines the amount of translation for a given amount of rotation. A screw configuration is defined by one value that represents the amount of rotation about its first reference frame's z-axis. Screws can be used as passive joints, or as active joints (motors).<br>
</li>

<li><strong>Spherical joints</strong>: spherical joints have three DoF and are used to describe rotational movements (with 3 DoF) between objects. Their configuration is defined by three values that represent the amount of rotation around their first reference frame's x-, y- and z-axis. The three values that define a spherical joint's configuration are specified as <a href="eulerAngles.htm">Euler angles</a>. In some situations, a spherical joint can be thought of as 3 concurrent and orthogonal to each other joints, that are parented in a hierarchy-chain. The analogy is however only valid while all revolute joints keep an orientation distinct from any of the two others: indeed, should two joints come close to coincide, a singular situation might appear and the mechanism might lose one DoF. This does never happen with spherical joints that are internally handled to avoid this kind of situation. Spherical joints are always passive joints, and cannot act as motors. </li>

<p align=center><img src="images/jointDescription2.jpg"></p>
<p class=imageLabel>[Two equivalent mechanisms (in this configuration): spherical joint (left) and 3 revolute joints (right)]</p>
<br>


<p align=center><img src="images/jointDescription3.jpg"></p>
<p class=imageLabel>[Two non-equivalent mechanisms: the right configuration is close to a singularity]</p>
<br>

<p>A joint is used to allow for a relative movement between its parent and its children. When a parent-child relationship is built between a joint and an object, the object is attached to the joint's second reference frame, thus, a change of the joint's configuration (intrinsic position) will directly be reflected onto its children. New joints can be added to a <a href="scenes.htm">scene</a> with [Menu bar --&gt; Add --&gt; Joints].
</p>

<br>
<table class=subsectionTable><tr class=subsectionTd><td class=subsectionTd>
<a name="modes"></a>Joint modes
</td></tr></table>

<p>A joint can be in one of following modes:
</p>

<li><strong>Passive mode</strong>: in this mode the joint is not directly controlled and will act as a fixed link. The user can however change the joint's position with appropriate <a href="apisOverview.htm">API</a> function calls (e.g. <a href="regularApi/simSetJointPosition.htm">sim.setJointPositon</a> or <a href="regularApi/simSetSphericalJointMatrix.htm">sim.setSphericalJointMatrix</a>).<br>
</li>

<li><strong>Dependent mode</strong>: in this mode, the joint position is directly linked (dependent) to another joint position through a linear equation.<br>
</li>

<li><strong>Torque or force mode</strong>: in this mode, the joint is simulated by the <a href="dynamicsModule.htm">dynamics module</a>, if and only if it is dynamically enabled (refer to the section on <a href="designingDynamicSimulations.htm">designing dynamic simulations</a> for more information). When dynamically enabled, a joint can be free or controlled in Force/torque, in velocity or in position. Screws cannot be operated in torque or force mode (however it is possible to obtain a similar behaviour by linking a revolute and prismatic joint programmatically), and spherical joints can only be free in torque or force mode.
</li>

<li class=tabTab>When the joint motor is disabled, the joint is free and only constrained by its limits.
</li>

<li class=tabTab>When the joint motor is enabled and the control loop is disabled, then the joint will try to reach the desired target velocity given the maximum torque/force it is capable to deliver. When that maximum torque/force is very high, the target velocity is instantaneously reached and the joint operates in velocity control, otherwise it operates at the specified torque/force until the desired target velocity is reached (torque/force control).
</li>

<li class=tabTab>When the joint motor is enabled and the control loop is enabled, then the user has 3 control modes available:</li>

<li class=fourTabs><em>Custom control</em>: a <a href="jointCallbackFunctions.htm">joint callback function</a> will be in charge of controlling the dynamic behaviour of the joint, allowing you to control the joint with any imaginable algorithm. </li>


<li class=fourTabs><em>Position control (PID)</em>: the joint will be controlled in position via a PID controller that will adjust the joint velocity in following way (the <em>&#916;t</em> divider is to keep the controller independent of the selected controller time step): </li>

<p align=center><img src="images/jointDescription5.jpg"></p>
<br>


<li class=fourTabs><em>Spring-damper mode</em>: the joint will act like a spring-damper system via a force/torque modulation: </li>

<p align=center><img src="images/jointDescription6.jpg"></p>
<br>


<br>
<table class=subsectionTable><tr class=subsectionTd><td class=subsectionTd>
<a name="controller"></a>Joint controllers
</td></tr></table>

<p>There are many different ways a joint can be controlled. In following section, we differentiate betwen a <em><strong>loose</strong></em> controller and a <em><strong>precise</strong></em> controller: a <em><strong>loose</strong></em> joint controller will not be able to provide new control values in each possible regulation step (e.g. some regulation steps might/will be skipped, but control is still possible). A <em><strong>precise</strong></em> joint controller on the other hand, will be able to provide control values in each possible regulation step.</p>

<p>First, the approach to take for controlling a joint will depend on the joint mode:</p>

<li><a href="#nonForceTorqueMode">The joint is not in force/torque mode</a>.</li>
<li><a href="#forceTorqueMode">The joint operates in force/torque mode</a>.</li>

<p>The differentiation comes from the fact that a joint that operates in force/torque mode will be handled by the physics engine. And the physics engine will perform by default 10 times more calculation steps than the simulation loop: the simulation loop runs at 20Hz (in simulation time), while the physics engine runs at 200Hz (also in simulation time). That default behaviour can entirely be configured if required.</p>

<p><strong><a name="nonForceTorqueMode"></a>If the joint is not in force/torque mode</strong>: if the joint is not in force/torque mode, then you can directly (and instantaneously) set its position via the <a href="regularApi/simSetJointPosition.htm">sim.setJointPosition</a> API function (or similar, e.g. <a href="b0RemoteApi-cpp.htm#simxSetJointPosition">simxSetJointPosition</a> for the B0-based remote API, or <a href="remoteApiFunctions.htm#simxSetJointPosition">simxSetJointPosition</a> for the legacy remote API). You can do this from a <a href="childScripts.htm">child script</a>, from a <a href="plugins.htm">plugin</a>, from a <a href="rosInterfaces.htm">ROS</a> node, from a <a href="blueZeroPlugin.htm">BlueZero</a> node, or from a <a href="remoteApiOverview.htm">remote API</a> client. If you do this from a child script, then it should be done inside of the <em>actuation section</em> of the <a href="childScripts.htm">child script</a>.</p>

<p>In following threaded <a href="childScripts.htm">child script</a> example, the joint is controlled <em><strong>loosely</strong></em>  in position, and there is no synchronization with the simulation loop:</p>

<pre class=lightRedBox>-- Following script should run threaded:

jointHandle=sim.getObjectHandle('/Revolute_joint')

sim.setJointPosition(jointHandle,90*math.pi/180) -- set the position to 90 degrees
sim.wait(2) -- wait 2 seconds (in simulation time)
sim.setJointPosition(jointHandle,180*math.pi/180) -- set the position to 180 degrees
sim.wait(1) -- wait 1 second (in simulation time)
sim.setJointPosition(jointHandle,0*math.pi/180) -- set the position to 0 degrees
etc.</pre>

<p>In following threaded <a href="childScripts.htm">child script</a> example, the joint is controlled <strong>precisely</strong> in position in each simulation step, i.e. the thread is synchronized with the simulation loop:</p>

<pre class=lightRedBox>-- Following script should run threaded:

local initialForbidLevel=sim.setThreadAutomaticSwitch(false) -- Automatic thread switching disabled
jointHandle=sim.getObjectHandle('/Revolute_joint')

sim.setJointPosition(jointHandle,90*math.pi/180) -- set the position to 90 degrees
sim.switchThread() -- the thread resumes in next simulation step (i.e. when t becomes t+dt)
sim.setJointPosition(jointHandle,180*math.pi/180) -- set the position to 180 degrees
sim.switchThread() -- the thread resumes in next simulation step
sim.setJointPosition(jointHandle,0*math.pi/180) -- set the position to 0 degrees
sim.switchThread() -- the thread resumes in next simulation step
-- etc.
sim.setThreadAutomaticSwitch(initialForbidLevel) -- Restore the automatic thread switching

-- In above code, a new joint position is applied in each simulation step
</pre>

<p>When you try to control a joint that is not in force/torque mode from an external application (e.g. via the <a href="remoteApiOverview.htm">remote API</a>, <a href="rosInterfaces.htm">ROS</a> or <a href="blueZeroPlugin.htm">BlueZero</a>), then the external controller will run asynchronously to CoppeliaSim (i.e. similar to the non-synchronized code of a threaded <a href="childScripts.htm">child script</a>). This is fine most of the time for <strong><em>loose</em></strong> control, but if you wish to control the position of the joint <strong><em>precisely</em></strong> in each simulation loop, you will have to run CoppeliaSim in synchronous mode, and the external controller (e.g. the remote API client) will have to trigger each simulation step explicitely. </p>
<p>Following illustrates a C++ <a href="b0RemoteApiOverview.htm">B0-based remote API</a> client that does this:</p>

<pre class=lightBlueBox>bool doNextStep=false;

void simulationStepDone_CB(std::vector&lt;msgpack::object&gt;* msg)
{
    doNextStep=true;
}

int main(int argc,char* argv[])
{
    ...
    client.simxSynchronous(true); // enable the synchronous mode
    client.simxGetSimulationStepDone(client.simxDefaultSubscriber(simulationStepDone_CB)); // callback when step finished
    client.simxStartSimulation(client.simxDefaultPublisher()); // start the simulation

    client.simxSetJointPosition(jointHandle,90.0f*3.1415f/180.0f,client.simxDefaultPublisher()); // set the joint to 90 degrees
    client.simxSynchronousTrigger(); // start one simulation step
    while (!doNextStep) // wait until simulation step finished
        client.simxSpinOnce();
        
    doNextStep=false;
    client.simxSetJointPosition(jointHandle,180.0f*3.1415f/180.0f,client.simxDefaultPublisher()); // set the joint to 180 degrees
    client.simxSynchronousTrigger(); // start one simulation step
    while (!doNextStep) // wait until simulation step finished
        client.simxSpinOnce();
        
    doNextStep=false;
    client.simxSetJointPosition(jointHandle,0.0f*3.1415f/180.0f,client.simxDefaultPublisher()); // set the joint to 0 degrees
    client.simxSynchronousTrigger(); // start one simulation step
    while (!doNextStep) // wait until simulation step finished
        client.simxSpinOnce();
    ...
}</pre>

<p>Refer to <a href="b0RemoteApiModusOperandi.htm#synchronous">this page</a> for details on how the B0-based remote API synchronous mode operates exactly. The approach is similar with ROS or BlueZero.</p>
<p>Following does the same, however with a <a href="legacyRemoteApiOverview.htm">legacy remote API</a> client:</p>

<pre class=lightBlueBox>...
simxSynchronous(clientId,1); // enable the synchronous mode (client side). The server side (i.e. CoppeliaSim) also needs to be enabled.
simxStartSimulation(clientId,simx_opmode_oneshot); // start the simulation
simxSetJointPosition(clientId,jointHandle,90.0f*3.1415f/180.0f,simx_opmode_oneshot); // set the joint to 90 degrees
simxSynchronousTrigger(clientId); // trigger next simulation step. Above commands will be applied
simxSetJointPosition(clientId,jointHandle,180.0f*3.1415f/180.0f,simx_opmode_oneshot); // set the joint to 180 degrees
simxSynchronousTrigger(clientId); // next simulation step executes. Above commands will be applied
simxSetJointPosition(clientId,jointHandle,0.0f*3.1415f/180.0f,simx_opmode_oneshot); // set the joint to 0 degrees
...</pre>

<p>Refer to <a href="remoteApiModusOperandi.htm#synchronous">this page</a> for details on how the legacy remote API synchronous mode operates exactly. The approach is similar with ROS or BlueZero.</p>


<p><strong><a name="forceTorqueMode"></a>If the joint is in force/torque mode</strong>: if the joint operates in force/torque mode and is <a href="designingDynamicSimulations.htm#dynamicallyEnabledJoints">dynamically enabled</a>, then it will be indirectly handled by the physics engine. If your joint's motor is not enabled, then your joint is not controlled (i.e. it will be free). Otherwise, your joint can be in following two dynamic modes:</p>

<li><a href="#controlLoopDisabled">The joint's motor is enabled, but the control loop is disabled</a>. Use this mode when you want to <strong><em>precisely</em></strong> custom control your joint from an external application (e.g. force/torque control, PID, etc.). Use this mode also, when you want to <em><strong>loosely</strong></em>  control your joint in force/torque mode, or for velocity control (e.g. robot wheel motors).</li>
<li><a href="#controlLoopEnabled">The joint's motor is enabled, and the control loop is enabled</a>. Use this mode when your joint needs to act as a spring/damper, or if you want to <strong><em>precisely</em></strong> custom control your joint from within CoppeliaSim, or if you want to <em><strong>loosely</strong></em>  control your joint in position control from an external application.</li>

<p><a name="controlLoopDisabled"></a>If your <strong>joint's motor is enabled, but the control loop is disabled</strong>, then the physics engine will apply the specified <strong>Maximum force/torque</strong>, and accelerate the joint until the <strong>target velocity</strong> is reached. If the load is small and/or the maximum force/torque high, that target velocity will be reached quickly. Otherwise, it will take some time, or, if the force/torque is not large enough, the target velocity will never be reached. You can programmatically adjust the target velocity with <a href="regularApi/simSetJointTargetVelocity.htm">sim.setJointTargetVelocity</a> (or for example, in case of the B0-based remote API: <a href="b0RemoteApi-cpp.htm#simxSetJointTargetVelocity">simxSetJointTargetVelocity</a>, or, in case of the legacy remote API: <a href="remoteApiFunctions.htm#simxSetJointTargetVelocity">simxSetJointTargetVelocity</a>), and the maximum force/torque with <a href="regularApi/simSetJointMaxForce.htm">sim.setJointMaxForce</a> (or for example, in case of the B0-based remote API: <a href="b0RemoteApi-cpp.htm#simxSetJointMaxForce">simxSetJointMaxForce</a>, or in case of the the legacy remote API: <a href="remoteApiFunctions.htm#simxSetJointMaxForce">simxSetJointMaxForce</a>). You should be very careful before writing  a <strong><em>precise</em></strong> joint controller for a joint in force/torque mode from a <a href="childScripts.htm">child script</a> for following reason:</p>

<p>By default, the simulation loop runs with a time step of 50ms (in simulation time). But the physics engine will run with a time step of 5ms, i.e. 10 times more often. A child script will be called in each simulation step, but not in each physics engine calculation step. This means that if you control a joint from a child script in a <em>regular way</em>, you will only be able to provide new control values once for 10 physics engine calculation steps: you will be missing 9 steps. One way to overcome this would be to change the default <a href="simulationPropertiesDialog.htm">simulation settings</a> and to specify a simulation <strong>time step</strong> of 5ms, instead of 50ms. This works fine, but remember that all other calculations (e.g. <a href="visionSensors.htm">vision sensors</a>, <a href="proximitySensors.htm">proximity sensors</a>, <a href="distanceCalculation.htm">distance calculations</a>, <a href="kinematics.htm">IK</a>, etc.) will also run 10 times more often, and finally slow down your simulation (most of the time you won't need such a high refresh rate for the other calculation modules. But the physics engine requires such a high refresh rate). Another, much better option, would be to use a <a href="jointCallbackFunctions.htm">joint callback function</a> (or a <a href="dynCallbackFunctions.htm">dynamics callback function</a>) as will be explained further down.</p>

<p>If, one the other hand, you want to run a <em><strong>precise</strong></em> and regular joint controller externally (e.g. from a <a href="remoteApiOverview.htm">remote API</a> client,  a <a href="rosInterfaces.htm">ROS</a> node or a <a href="blueZeroPlugin.htm">BlueZero</a> node), then you have no other option than to set the simulation loop to the same rate as the physics engine rate, then run CoppeliaSim in synchronous mode, and the external controller (e.g. the remote API client) will have to trigger each simulation step explicitely. </p>
<p>Following illustrates a C++ <a href="b0RemoteApiOverview.htm">B0-based remote API</a> client that does this:</p>

<pre class=lightBlueBox>bool doNextStep=false;

void simulationStepDone_CB(std::vector&lt;msgpack::object&gt;* msg)
{
    doNextStep=true;
}

int main(int argc,char* argv[])
{
    ...
    client.simxSynchronous(true); // enable the synchronous mode
    client.simxGetSimulationStepDone(client.simxDefaultSubscriber(simulationStepDone_CB)); // callback when step finished
    client.simxStartSimulation(client.simxDefaultPublisher()); // start the simulation

    // set the desired force and target velocity:
    client.simxSetJointMaxForce(jointHandle,1.0f,client.simxDefaultPublisher());
    client.simxSetJointTargetVelocity(jointHandle,180.0f*3.1415f/180.0f,client.simxDefaultPublisher());
    client.simxSynchronousTrigger(); // start one simulation step
    while (!doNextStep) // wait until simulation step finished
        client.simxSpinOnce();
        
    doNextStep=false;
    // set the desired force and target velocity:
    client.simxSetJointMaxForce(jointHandle,0.5f,client.simxDefaultPublisher());
    client.simxSetJointTargetVelocity(jointHandle,180.0f*3.1415f/180.0f,client.simxDefaultPublisher());
    client.simxSynchronousTrigger(); // start one simulation step 
    while (!doNextStep) // wait until simulation step finished
        client.simxSpinOnce();
        
    doNextStep=false;
    // set the desired force and target velocity:
    client.simxSetJointMaxForce(jointHandle,2.0f,client.simxDefaultPublisher());
    client.simxSetJointTargetVelocity(jointHandle,180.0f*3.1415f/180.0f,client.simxDefaultPublisher());
    client.simxSynchronousTrigger(); // start one simulation step
    while (!doNextStep) // wait until simulation step finished
        client.simxSpinOnce();
    ...
}</pre>

<p>Refer to <a href="b0RemoteApiModusOperandi.htm#synchronous">this page</a> for details on how the B0-based remote API synchronous mode operates exactly. The approach is similar with ROS or BlueZero.</p>

<p>Following does the same, however with a <a href="legacyRemoteApiOverview.htm">legacy remote API</a> client:</p>

<pre class=lightBlueBox>...
simxSynchronous(clientId,1); -- enable the synchronous mode (client side). The server side (i.e. CoppeliaSim) also needs to be enabled.
simxStartSimulation(clientId,simx_opmode_oneshot); // start the simulation
simxSetJointMaxForce(clientId,jointHandle,1.0f,simx_opmode_oneshot); // set the joint force/torque
simxSetJointTargetVelocity(clientId,jointHandle,180.0f*3.1415f/180.0f,simx_opmode_oneshot); // set the joint target velocity
simxSynchronousTrigger(clientId); // trigger next simulation step. Above commands will be applied
simxSetJointMaxForce(clientId,jointHandle,0.5f,simx_opmode_oneshot); // set the joint force/torque
simxSetJointTargetVelocity(clientId,jointHandle,180.0f*3.1415f/180.0f,simx_opmode_oneshot); // set the joint target velocity
simxSynchronousTrigger(clientId); // next simulation step executes. Above commands will be applied
simxSetJointMaxForce(clientId,jointHandle,2.0f,simx_opmode_oneshot); // set the joint force/torque
simxSetJointTargetVelocity(clientId,jointHandle,180.0f*3.1415f/180.0f,simx_opmode_oneshot); // set the joint target velocity
...</pre>

<p>Refer to <a href="remoteApiModusOperandi.htm#synchronous">this page</a> for details on how the legacy remote API synchronous mode operates exactly. The approach is similar with ROS or BlueZero.</p>


<p><a name="controlLoopEnabled"></a>If your <strong>joint's motor is enabled, and the control loop is also enabled</strong>, then the physics engine will handle the joint according to the setting: your joint can operate in position control (i.e. PID control), in a spring/damper mode, or in custom control. PID and spring/damper parameters can be updated from a <a href="childScripts.htm">child script</a>, from a <a href="remoteApiOverview.htm">remote API</a> client,  from a <a href="rosInterfaces.htm">ROS</a> or <a href="blueZeroPlugin.htm">BlueZero</a> node. Refer to <a href="objectParameterIDs.htm">object parameter IDs</a> 2002-2004, and 2018-2019. Desired target positions can be set with <a href="regularApi/simSetJointTargetPosition.htm">sim.setJointTargetPosition</a> (or, for example, from a B0-based remote API client: <a href="b0RemoteApi-cpp.htm#simxSetJointTargetPosition">simxSetJointTargetPosition</a>, or from a legacy remote API client: <a href="remoteApiFunctions.htm#simxSetJointTargetPosition">simxSetJointTargetPosition</a>). When you need a <em><strong>precise</strong></em> custom controller, then you should use a <a href="jointCallbackFunctions.htm">joint callback function</a> instead (or a <a href="dynCallbackFunctions.htm">dynamics callback function</a>).</p>

<p>Finally, if you need a precise PID or custom controller that is implemented in an external application, you need to make sure that the simulation step is the same as the physics engine calculation step: by default, CoppeliaSim's simulation loop runs at 20Hz (in simulation time), while the physics engine runs at 200Hz. You can adjust the simulation step size in the <a href="simulationPropertiesDialog.htm">simulation setting</a>. You also need to make sure you run CoppeliaSim in synchronous mode. </p>
<p>Following illustrates a C++ <a href="b0RemoteApiOverview.htm">B0-based remote API</a> client that does this:</p>

<pre class=lightBlueBox>bool doNextStep=false;

void simulationStepDone_CB(std::vector&lt;msgpack::object&gt;* msg)
{
    doNextStep=true;
}

int main(int argc,char* argv[])
{
    ...
    client.simxSynchronous(true); // enable the synchronous mode
    client.simxGetSimulationStepDone(client.simxDefaultSubscriber(simulationStepDone_CB)); // callback when step finished
    client.simxStartSimulation(client.simxDefaultPublisher()); // start the simulation

    // set the desired target position:
    client.simxSetJointTargetPosition(jointHandle,90.0f*3.1415f/180.0f,client.simxDefaultPublisher());
    client.simxSynchronousTrigger(); // start one simulation step
    while (!doNextStep) // wait until simulation step finished
        client.simxSpinOnce();
        
    doNextStep=false;
    // set the desired target position:
    client.simxSetJointTargetPosition(jointHandle,180.0f*3.1415f/180.0f,client.simxDefaultPublisher());
    client.simxSynchronousTrigger(); // start one simulation step
    while (!doNextStep) // wait until simulation step finished
        client.simxSpinOnce();
        
    doNextStep=false;
    // set the desired target position:
    client.simxSetJointTargetPosition(jointHandle,0.0f*3.1415f/180.0f,client.simxDefaultPublisher());
    client.simxSynchronousTrigger(); // start one simulation step
    while (!doNextStep) // wait until simulation step finished
        client.simxSpinOnce();
    ...
}</pre>

<p>Following does the same, however with a <a href="legacyRemoteApiOverview.htm">legacy remote API</a> client:</p>

<pre class=lightBlueBox>...
simxSynchronous(clientId,1); -- enable the synchronous mode (client side). The server side (i.e. CoppeliaSim) also needs to be enabled.
simxStartSimulation(clientId,simx_opmode_oneshot); // start the simulation
simxSetJointTargetPosition(clientId,jointHandle,90.0f*3.1415f/180.0f,simx_opmode_oneshot); // set the desired joint position
simxSynchronousTrigger(clientId); // trigger next simulation step. Above commands will be applied
simxSetJointTargetPosition(clientId,jointHandle,180.0f*3.1415f/180.0f,simx_opmode_oneshot); // set the desired joint position
simxSynchronousTrigger(clientId); // next simulation step executes. Above commands will be applied
simxSetJointTargetPosition(clientId,jointHandle,0.0f*3.1415f/180.0f,simx_opmode_oneshot); // set the desired joint position
...</pre>

<p>You can also have a remote API client provide control values for a custom joint controller implemented in a joint callback function, by providing values, for instance via signals, to that joint callback function. For example, from a C++ <a href="b0RemoteApiOverview.htm">B0-based remote API</a> client:</p>

<pre class=lightBlueBox>bool doNextStep=false;

void simulationStepDone_CB(std::vector&lt;msgpack::object&gt;* msg)
{
    doNextStep=true;
}

int main(int argc,char* argv[])
{
    ...
    client.simxSynchronous(true); // enable the synchronous mode
    client.simxGetSimulationStepDone(client.simxDefaultSubscriber(simulationStepDone_CB)); // callback when step finished
    client.simxStartSimulation(client.simxDefaultPublisher()); // start the simulation

    // set the desired target position:
    simxSetFloatSignal("myDesiredTorque",1.0f,client.simxDefaultPublisher());
    simxSetFloatSignal("myDesiredTarget",90.0f*3.1415f/180.0f,client.simxDefaultPublisher());
    client.simxSynchronousTrigger(); // start one simulation step
    while (!doNextStep) // wait until simulation step finished
        client.simxSpinOnce();
    ...
}</pre>

<p>In above example, your joint callback function could fetch those two signals (with <a href="regularApi/simGetDoubleSignal.htm">sim.getDoubleSignal</a>) before doing the control.</p>

<p>Following does the same, however with a <a href="legacyRemoteApiOverview.htm">legacy remote API</a> client:</p>

<pre class=lightBlueBox>...
simxSynchronous(clientId,1); -- enable the synchronous mode (client side). The server side (i.e. CoppeliaSim) also needs to be enabled.
simxStartSimulation(clientId,simx_opmode_oneshot); // start the simulation
simxSetFloatSignal(clientId,"myDesiredTorque",1.0f,simx_opmode_oneshot); // set the signal value
simxSetFloatSignal(clientId,"myDesiredTarget",90.0f*3.1415/180.0f,simx_opmode_oneshot); // set the signal value
simxSynchronousTrigger(clientId); // trigger next simulation step. Above commands will be applied
...</pre>

<br>
<br>

 </tr>
</table> 
</div>  
  
  
</body>

</html>
